﻿// -------------------------------------------------------------------------
//    @FileName         :    NFLogicDynamicModule.cpp
//    @Author           :    gaoyi
//    @Date             :    23-8-2
//    @Email			:    445267987@qq.com
//    @Module           :    NFLogicDynamicModule
//
// -------------------------------------------------------------------------

#include "NFLogicDynamicModule.h"

#include "NFSysMsgUtil.h"
#include "proto_cs_cmd.nanopb.h"

#if NF_PLATFORM == NF_PLATFORM_WIN
#else
#include <netinet/in.h>
#endif
#include <NFSessionUtil.h>
#include <NFLogicCommon/CustomPacketParse.h>
#include <NFLogicCommon/NFOperatingStatistcsMgr.h>
#include <NFLogicCommon/NFScopedMessageHead.h>
#include <NFLogicCommon/NFWatchTime.h>

#include "Base/NFPacketSendUtil.h"
#include "Base/NFServerUtil.h"
#include "proto_need.nanopb.h"
#include "NFSession.h"
#include "NFPlayer.h"

NFLogicDynamicModule::NFLogicDynamicModule(NFIPluginManager *p): NFMMODynamicModule(p)
{
}

NFLogicDynamicModule::~NFLogicDynamicModule()
{
}

int NFLogicDynamicModule::OnHandleClientMessage(uint64_t unLinkId, NFDataPackage &packet)
{
    uint64_t sessionId = packet.nParam1;
    NFSession *pSession = NFSessionUtil::GetSessionObj(sessionId);
    CHECK_EXPR(pSession, -1, "CServerUtil::GetSessionObj Failed ID:{}", sessionId);

    NFScopedMessageHead scopedMessageHead(pSession->GetGlobalId(), packet.nMsgId, packet.nMsgSeq);

    NFAutoLogContext autoLogContext(pSession->GetOpenID(), pSession->GetRoleId(), packet.mModuleId, packet.nMsgId, packet.nMsgSeq);

    CHECK_EXPR(proto_ff::Proto_CS_CMD_IsValid(packet.nMsgId), -1, "invalid msg id:{}", packet.nMsgId);
    LOGSVR_TRACE_IF(packet.nMsgId != E_CS_HEARTBEAT_REQ, "recv msg:" << proto_ff::Proto_CS_CMD_Name(static_cast<proto_ff::Proto_CS_CMD>(packet.nMsgId)))

    if (m_pObjPluginManager->IsServerStopping())
    {
        NFLogError(NF_LOG_DEFAULT, packet.nParam1, "Logic Server is Stopping, drop client msg:{}", packet.nMsgId);
        return -1;
    }

    int iRetCode = pSession->ActiveAndCheck(packet.nMsgId, 0, NF_ADJUST_TIMENOW(), 0);
    CHECK_PLAYER_RET(pSession->GetRoleId(), iRetCode, "Session:{} of Role:{}  Recv msg Check Invalid!MsgID:{}", pSession->GetGlobalId(), pSession->GetRoleId(), packet.nMsgId);

#ifdef NF_DEBUG_MODE
    NFWatchTime oWatchTime(packet.nMsgId, 0, packet.nMsgLen, ENST_NET_IN, &iRetCode);
#endif

    proto_ff::Proto_CSReq req;
    CLIENT_MSG_PROCESS_WITH_PRINTF(packet, req);

    uint64_t ullTimeNow = NFGetTime();
    if (ullTimeNow > (uint64_t) req.timestamp() + 100000)
    {
        LOGSVR_ERROR("recv packet delay:" << (ullTimeNow - req.timestamp()));
    }

    iRetCode = pSession->CheckPkgRate(packet.nMsgId);
    if (iRetCode)
    {
        NFPacketSendUtil::SendErrToClient(pSession, packet.nMsgId, (proto_ff::Proto_CS_ErrorCode) iRetCode);
        return 0;
    }

    if (packet.nMsgId != proto_ff::E_CS_LOGIN_REQ
        && packet.nMsgId != proto_ff::E_CS_PRELOGIN_UID_REQ
        && packet.nMsgId != proto_ff::E_CS_LOG_CHECK_POINT_REQ
        && packet.nMsgId != proto_ff::E_CS_GETROLE_REQ
        && packet.nMsgId != proto_ff::E_CS_LINEUP_CANCEL_REQ
        && packet.nMsgId != proto_ff::E_CS_LOGIN_FAST_ROLE_REQ
        && packet.nMsgId != proto_ff::E_CS_HEARTBEAT_REQ
        && packet.nMsgId != proto_ff::E_CS_CREATE_ROLE_REQ
        && packet.nMsgId != proto_ff::E_CS_SNS_FRIEND_QUERY_REQ
        && packet.nMsgId != proto_ff::E_CS_BATTLESVR_RTT_REQ
        && packet.nMsgId != proto_ff::E_CS_ROOM_QUERY_REQ
        && packet.nMsgId != proto_ff::E_CS_MALL_LIST_REQ
        && packet.nMsgId != proto_ff::E_CS_RELAY_REQ
        && packet.nMsgId != proto_ff::E_CS_DELETE_ROLE_REQ
        && packet.nMsgId != proto_ff::E_CS_TSS_SDK_SEND_DATA_REQ
        && packet.nMsgId != proto_ff::E_CS_FAN_TYPE_REPORT_REQ
        && packet.nMsgId != proto_ff::E_CS_HEALTH_GET_INFO_REQ
        && packet.nMsgId != proto_ff::E_CS_HEALTH_DONE_REMIND_REQ)
    {
        NFPlayer *pPlayer = pSession->GetPlayer();
        if (!pPlayer)
        {
            LOGSVR_ERROR("ERR_CODE_LOGIN_STATE_ERR: player not exits");
            NFPacketSendUtil::SendErrToClient(pSession, packet.nMsgId, proto_ff::ERR_CODE_LOGIN_STATE_ERR);
            return 0;
        }

        if (!pPlayer->IsInit() || pPlayer->GetPlayerStatus() != CACHE_STATUS_ONLINE)
        {
            LOGSVR_ERROR("ERR_CODE_LOGIN_STATE_ERR: player not online.");
            NFPacketSendUtil::SendErrToClient(pSession, packet.nMsgId, proto_ff::ERR_CODE_LOGIN_STATE_ERR);
            return 0;
        }
    }

    //客户端包去重
    if (!IS_CS_REQ_MSG_IN_BLACKLIST(packet.nMsgId) && packet.nMsgSeq <= pSession->GetClientSeq())
    {
        LOGSVR_DEBUG("ClientSeq:" << packet.nMsgSeq << " <= ServerClientSeq:" << pSession->GetClientSeq() << ", ServerSeq:" << pSession->GetServerSeq()
            << " Client MsgID:" << packet.nMsgId << " reduplicated.");

        //return 0;
    }

    //保存客户端包序列号
    pSession->StoreClientSeq(packet.nMsgSeq);

    //重连上来之后，客户端第一个包告知服务器收到的最后一个服务器包序列号
    //服务器将大于次序列号的包重发
    if (packet.nMsgId == proto_ff::E_CS_RELAY_REQ)
    {
        LOGSVR_ERROR("ClientSeq:" << packet.nMsgSeq << ", ClientServerSeq:" << req.server_seq() << " < ServerSeq:" << pSession->GetServerSeq()
            << "	MsgID:" << packet.nMsgId << ", call SendCachedMsgRes.");

        NFPlayer *pPlayer = pSession->GetPlayer();
        if (!pPlayer || !pPlayer->GetRoleDetailSyned())
        {
            return NFPacketSendUtil::SendErrToClient(pSession, proto_ff::E_CS_RELAY_REQ, proto_ff::ERR_CODE_NEED_RELOGIN);
        }

        iRetCode = pPlayer->SendCachedMsgRes(req.server_seq());

        //打印日志
        LOGSVR_DEBUG("SendCachedMsgRes retcode:" << iRetCode << ", client cmd:" << req.server_seq() << ", clientSeq:" << packet.nMsgSeq
            << " ClientServerSeq:" << req.server_seq() << " Session Seq:" << pSession->GetServerSeq() << "!");

        if (iRetCode != 0)
        {
            //需要重发Login,Clear Session Cache
            if (iRetCode < -1)
            {
                pPlayer->CleanupCache();

                //玩家在服务器状态正常
                if (pPlayer->GetPlayerStatus() == CACHE_STATUS_ONLINE)
                {
                    iRetCode = NFPacketSendUtil::SendErrToClient(pSession, proto_ff::E_CS_RELAY_REQ, proto_ff::ERR_CODE_NEED_RELOGIN);
                }
            }

            return iRetCode;
        }
        //如果成功，则将Player状态置为LOGIN
        else if (pPlayer->GetPlayerStatus() != CACHE_STATUS_ONLINE)
        {
            pPlayer->SetPlayerStatus(CACHE_STATUS_ONLINE);
        }

        proto_ff::Proto_CSRsp rsp;
        NFPacketSendUtil::SendToClientDirectly(pSession, proto_ff::E_CS_RELAY_RSP, &rsp);

        return iRetCode;
    }

    iRetCode = OnHandleClientMessage(packet, pSession, req);
    if (iRetCode != 0)
    {
#ifdef NF_DEBUG_MODE
        std::string errMsg = NFLogMgr::Instance()->GetErrorInfo();
        NFSysMsgUtil::SendSysMsg(pSession->GetPlayer(), proto_ff::E_SysMsg_Show_Type_B, 100, errMsg);
#endif
        if (proto_ff::Proto_CS_ErrorCode_IsValid(iRetCode))
        {
            NFPacketSendUtil::SendErrToClient(pSession, packet.nMsgId,  iRetCode);
        }
        else
        {
            NFPacketSendUtil::SendErrToClient(pSession, packet.nMsgId,  ERR_CODE_SYSTEM_ERROR);
        }
    }
    return 0;
}

int NFLogicDynamicModule::OnHandleClientMessage(NFDataPackage &packet, NFSession *pSession, const proto_ff::Proto_CSReq &req)
{
    NFLogError(NF_LOG_DEFAULT, 0, "nMsgId:{} not handle", packet.nMsgId);
    return -1;
}
